package com.iplant.mes.serviceImpl;

import com.iplant.ams.service.po.dms.fault.DMSFaultBase;
import com.iplant.ams.serviceImpl.DFBServiceImpl;
import com.iplant.aps.service.apsenum.aps.APSTaskStatus;
import com.iplant.aps.service.po.aps.APSTaskPartPoint;
import com.iplant.aps.service.po.aps.APSTaskPartPointDay;
import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.ServiceResult;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.general.CalendarTool;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.orm.ORMUtils;
import com.iplant.base.utils.sql.orm.PoService;
import com.iplant.base.utils.tasker.TaskTimerUtils;
import com.iplant.basic.service.basicenum.bfc.BFCMessageType;
import com.iplant.basic.service.basicenum.bpm.BPMEventModule;
import com.iplant.basic.service.basicenum.bpm.BPMHistoryTaskStatus;
import com.iplant.basic.service.basicenum.bpm.BPMTaskStatus;
import com.iplant.basic.service.basicenum.bpm.TaskQueryType;
import com.iplant.basic.service.po.bfc.BFCMessage;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.basic.service.po.bms.BMSRoleItem;
import com.iplant.basic.service.po.bpm.BPMActivitiHisTask;
import com.iplant.basic.service.po.bpm.BPMActivitiProcessInstance;
import com.iplant.basic.service.po.bpm.BPMActivitiTask;
import com.iplant.basic.service.po.fmc.FMCShift;
import com.iplant.basic.service.po.fmc.FMCStation;
import com.iplant.basic.serviceImpl.BFCServiceImpl;
import com.iplant.basic.serviceImpl.BMSServiceImpl;
import com.iplant.basic.serviceImpl.BPMServiceImpl;
import com.iplant.basic.serviceImpl.FMCServiceImpl;
import com.iplant.basic.serviceImpl.dao.bfc.BFCSystemConfigDAO;
import com.iplant.basic.utils.Constants;
import com.iplant.mes.service.EXCService;
import com.iplant.mes.service.mesenum.exc.EXCLineStopStatus;
import com.iplant.mes.service.mesenum.exc.EXCProductRepairItemStatus;
import com.iplant.mes.service.mesenum.exc.EXCProductRepairStatus;
import com.iplant.mes.service.mesenum.exc.EXCUnusualStatus;
import com.iplant.mes.service.mesenum.sfc.SFCTaskStatus;
import com.iplant.mes.service.mesenum.sfc.SFCWorkpieceCheckResult;
import com.iplant.mes.service.po.exc.*;
import com.iplant.mes.service.po.sfc.SFCTaskIPT;
import com.iplant.mes.service.po.sfc.SFCTaskSelf;
import com.iplant.mes.service.po.sfc.SFCWorkpieceRecord;
import com.iplant.mes.service.po.sfc.SFCWorkpieceResume;
import com.iplant.mes.serviceImpl.dao.exc.EXCUnusualTaskDAO;
import com.iplant.pdm.service.basicenum.pdm.PDMComponentTypes;
import com.iplant.pdm.service.po.bop.FPCRoutePartPoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class EXCServiceImpl implements EXCService {

    //region 构造函数
    public EXCServiceImpl() {
        Constants.BPMServiceMap.put(BPMEventModule.Exception_HANDLE, this);
    }
    //endregion

    //region 单实例

    private static EXCService Instance = null;

    public static EXCService getInstance() {
        if (Instance == null)
            Instance = new EXCServiceImpl();

        return Instance;
    }


    //endregion

    //region POService
    PoService<DMSFaultBase> mDMSFaultBaseService = ORMUtils.GetPoService(DMSFaultBase.class);
    PoService<EXCLineStop> mEXCLineStopService = ORMUtils.GetPoService(EXCLineStop.class);
    PoService<APSTaskPartPoint> mAPSTaskPartPointService = ORMUtils.GetPoService(APSTaskPartPoint.class);
    PoService<EXCProductRepair> mEXCProductRepairService = ORMUtils.GetPoService(EXCProductRepair.class);
    PoService<EXCProductRepairItem> mEXCProductRepairItemService = ORMUtils.GetPoService(EXCProductRepairItem.class);
    PoService<APSTaskPartPointDay> mAPSTaskPartPointDayService = ORMUtils.GetPoService(APSTaskPartPointDay.class);
    PoService<SFCWorkpieceResume> mSFCWorkpieceResumeService = ORMUtils.GetPoService(SFCWorkpieceResume.class);
    PoService<FPCRoutePartPoint> mFPCRoutePartPointService = ORMUtils.GetPoService(FPCRoutePartPoint.class);
    PoService<SFCWorkpieceRecord> mSFCWorkpieceRecordService = ORMUtils.GetPoService(SFCWorkpieceRecord.class);
    PoService<SFCTaskSelf> mSFCTaskSelfService = ORMUtils.GetPoService(SFCTaskSelf.class);
    PoService<SFCTaskIPT> mSFCTaskIPTService = ORMUtils.GetPoService(SFCTaskIPT.class);
    PoService<FMCStation> mFMCStationService = ORMUtils.GetPoService(FMCStation.class);
    PoService<BMSEmployee> mBMSEmployeeService = ORMUtils.GetPoService(BMSEmployee.class);
    PoService<EXCUnusualTask> mEXCUnusualTaskService = ORMUtils.GetPoService(EXCUnusualTask.class);
    //endregion

    //region 异常流程
    @Override
    public ServiceResult<EXCUnusualTask> BPM_QueryDefaultTask(BMSEmployee wLoginUser,
                                                              int wTaskID, int wEventID) {
        ServiceResult<EXCUnusualTask> wResult = new ServiceResult<>();
        wResult.Result = new EXCUnusualTask();
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);


            Map<String, Object> wParams = new HashMap<String, Object>();

            wParams.put("UpFlowID", wLoginUser.ID);
            wParams.put("Status", "0");

            EXCUnusualTask wEXCUnusualTask = EXCUnusualTaskDAO.getInstance().SelectPO(wLoginUser,
                    wParams, wErrorCode);
            if (wEXCUnusualTask != null && wEXCUnusualTask.ID > 0) {
                wEXCUnusualTask.FlowType = wEventID;
                wEXCUnusualTask.UpFlowID = wLoginUser.ID;
                wEXCUnusualTask.UpFlowName = wLoginUser.Name;
                wEXCUnusualTask.CreateTime = Calendar.getInstance();
                wEXCUnusualTask.EditTime = Calendar.getInstance();
                wEXCUnusualTask.HandleTime = CalendarTool.getBasicDate();

                //更新创建时间
                EXCUnusualTaskDAO.getInstance().EXC_UpdateCreateTimeByID(wLoginUser, wEXCUnusualTask.ID, wErrorCode);

                wResult.Result = wEXCUnusualTask;
            }

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());

        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error(e.toString());
        }
        return wResult;
    }


    @Override
    public ServiceResult<EXCUnusualTask> BPM_CreateTask(BMSEmployee wLoginUser,
                                                        BPMEventModule wEventID) {
        ServiceResult<EXCUnusualTask> wResult = new ServiceResult<>();
        wResult.Result = new EXCUnusualTask();
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            EXCUnusualTask wPo = new EXCUnusualTask();
            wPo.setUserInfo(wLoginUser);
            wPo.ID = 0;
            wPo.FlowType = wEventID.getValue();
            wPo.UpFlowID = wLoginUser.ID;
            wPo.UpFlowName = wLoginUser.Name;
            wPo.Status = 0;
            wPo.StatusText = "";
            wPo.CreateTime = Calendar.getInstance();
            wPo.EditTime = Calendar.getInstance();

            EXCUnusualTaskDAO.getInstance().UpdatePo(wLoginUser, wPo, wErrorCode);

            wResult.Result = wPo;

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error(e.toString());
        }
        return wResult;
    }

    @Override
    public ServiceResult<EXCUnusualTask> BPM_SubmitTask(BMSEmployee wLoginUser,
                                                        EXCUnusualTask wData) {
        ServiceResult<EXCUnusualTask> wResult = new ServiceResult<>();
        wResult.Result = wData;
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            if (wData.Status == EXCUnusualStatus.Confirm.getValue()) {
                wData.HandleTime = Calendar.getInstance();
                wData.StatusText = EXCUnusualStatus.Confirm.getLabel();
                //维护异常知识库
                if (StringUtils.isNotEmpty(wData.NewExcDescription)) {
                    DMSFaultBase wDMSFaultBase = new DMSFaultBase();
                    wDMSFaultBase.Code = "";
                    wDMSFaultBase.Active = 0;
                    wDMSFaultBase.Description = wData.NewExcDescription;
                    wDMSFaultBase.HandleWay = wData.NewExcMethods;
                    wDMSFaultBase.ExcType = wData.UnusualType;
                    wDMSFaultBase.Type = 2;
                    wDMSFaultBase.FileUrl = wData.NewExcUrls;
                    wDMSFaultBase.setUserInfo(wLoginUser);
                    wDMSFaultBase.DeviceTypeID = wData.DeviceTypeID;
                    ServiceResult<Integer> integerServiceResult =
                            DFBServiceImpl.getInstance().DMS_UpdateFaultBase(wLoginUser, wDMSFaultBase);
                    if (StringUtils.isNotEmpty(integerServiceResult.FaultCode)) {
                        wResult.FaultCode += integerServiceResult.FaultCode;
                        return wResult;
                    }

                    //推送通知消息给相关权限人员，维护知识库
                    List<BMSRoleItem> wBMSRoleItemList =
                            BMSServiceImpl.getInstance().BMS_QueryUserListByFunctionID(wLoginUser,
                                    80003).Result;
                    if (wBMSRoleItemList != null && wBMSRoleItemList.size() > 0) {
                        List<BFCMessage> wBFCMessageList = new ArrayList<>();
                        BFCMessage wMessage = null;
                        SimpleDateFormat wSDF = new SimpleDateFormat("yyyyMMdd");
                        int wShiftID = Integer.parseInt(wSDF.format(Calendar.getInstance().getTime()));
                        for (BMSRoleItem wItem : wBMSRoleItemList) {
                            // 发送任务消息到人员
                            wMessage = new BFCMessage();
                            wMessage.Active = 0;
                            wMessage.CompanyID = 0;
                            wMessage.CreateTime = Calendar.getInstance();
                            wMessage.EditTime = Calendar.getInstance();
                            wMessage.ID = 0;
                            wMessage.MessageID = integerServiceResult.Result;
                            wMessage.Title = wData.Code;
                            wMessage.MessageText = StringUtils.Format("【{0}】 {1}创建故障知识库维护消息，请及时处理。",
                                    BPMEventModule.FaultBaseRepairAudit.getLabel(), wLoginUser.Name);
                            wMessage.ModuleID = BPMEventModule.FaultBaseRepairAudit.getValue();
                            wMessage.ResponsorID = wItem.UserID;
                            wMessage.ShiftID = wShiftID;
                            wMessage.StationID = 0;
                            wMessage.Type = BFCMessageType.Notify.getValue();
                            wBFCMessageList.add(wMessage);
                        }
                        BFCServiceImpl.getInstance().BFC_UpdateMessageList(wLoginUser, wBFCMessageList);
                    }
                }
            }

            wData.setUserInfo(wLoginUser);
            wData.EditTime = Calendar.getInstance();
            EXCUnusualTaskDAO.getInstance().UpdatePo(wLoginUser, wData, wErrorCode);

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error(e.toString());
        }
        return wResult;
    }

    @Override
    public ServiceResult<EXCUnusualTask> BPM_GetTask(BMSEmployee wLoginUser, int wID) {
        ServiceResult<EXCUnusualTask> wResult = new ServiceResult<>();
        OutResult<Integer> wErrorCode = new OutResult<>(0);
        wResult.Result = EXCUnusualTaskDAO.getInstance().SelectPO(wLoginUser, wID, "", wErrorCode);
        wResult.AddFaultCode(wErrorCode);
        return wResult;
    }

    @Override
    public Class<EXCUnusualTask> GetTClass() {
        return EXCUnusualTask.class;
    }
    //endregion

    //region 异常统计
    @Override
    public ServiceResult<List<EXCUnusualTask>> BPM_QueryEmployeeAllWeb(BMSEmployee wLoginUser, Map<String,
            Object> wParams, Pagination wPagination) {
        ServiceResult<List<EXCUnusualTask>> wResult = new ServiceResult<>();
        wResult.Result = new ArrayList<>();
        OutResult<Integer> wErrorCode = new OutResult<>(0);
        try {
            int wStatus = StringUtils.parseInt(wParams.get("Status"));
            switch (wStatus) {
                case 0://待办
                    wParams.remove("CStartTime");
                    wParams.remove("CEndTime");
                    wParams.remove("DStartTime");
                    wParams.remove("DEndTime");
                    wParams.put("Status", "2,3");
                    wResult.Result = EXCUnusualTaskDAO.getInstance().SelectPOList(wLoginUser, wParams, wPagination,
                            wErrorCode);
                    break;
                case 1://已办
                    wParams.put("Status", "20,21,22");
                    wResult.Result = EXCUnusualTaskDAO.getInstance().SelectPOList(wLoginUser, wParams, wPagination,
                            wErrorCode);
                    break;
                default://全部
                    wParams.put("Status", "2,3,20,21,22");
                    wResult.Result = EXCUnusualTaskDAO.getInstance().SelectPOList(wLoginUser, wParams, wPagination,
                            wErrorCode);
                    break;
            }

            if (wResult.Result.size() == 0 || wStatus == 1) {
                return wResult;
            }

            // 待办数据处理
            List<EXCUnusualTask> wBaseList =
                    EXCUnusualTaskDAO.getInstance().BFC_GetUndoTaskList(wLoginUser,
                            wLoginUser.ID,
                            new ArrayList<>(Collections.singletonList(BPMEventModule.Exception_HANDLE.getValue()))
                            , wParams, Pagination.getNewMaxSize(), wErrorCode);
            if (wBaseList == null || wBaseList.size() == 0) {
                return wResult;
            }
            for (EXCUnusualTask wTaskBase : wBaseList) {
                wTaskBase.TagTypes = TaskQueryType.ToHandle.getValue();
                for (int i = 0; i < wResult.Result.size(); i++) {
                    if (wResult.Result.get(i).ID == wTaskBase.ID)
                        wResult.Result.set(i, wTaskBase);
                }
            }

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error(e.toString());
        }
        return wResult;
    }


    @Override
    public ServiceResult<List<EXCStatRate>> EXC_GetTypeRateList(BMSEmployee wLoginUser, int wUnusualType,
                                                                int wDeviceID, int wStationID, int wStatType,
                                                                Calendar wStartDate, Calendar wEndDate) {
        ServiceResult<List<EXCStatRate>> wResult = new ServiceResult<>();
        OutResult<Integer> wErrorCode = new OutResult<>(0);
        wResult.Result = EXCUnusualTaskDAO.getInstance().EXC_GetTypeRateList(wLoginUser, wUnusualType, wDeviceID,
                wStationID, wStatType, wStartDate, wEndDate, wErrorCode);
        wResult.AddFaultCode(wErrorCode);
        return wResult;

    }

    @Override
    public ServiceResult<List<EXCStatRate>> EXC_GetStationRateList(BMSEmployee wLoginUser, int wUnusualType,
                                                                   int wDeviceID, int wStationID, int wStatType,
                                                                   Calendar wStartDate, Calendar wEndDate) {
        ServiceResult<List<EXCStatRate>> wResult = new ServiceResult<>();
        OutResult<Integer> wErrorCode = new OutResult<>(0);
        wResult.Result = EXCUnusualTaskDAO.getInstance().EXC_GetStationRateList(wLoginUser, wUnusualType, wDeviceID,
                wStationID, wStatType, wStartDate, wEndDate, wErrorCode);
        wResult.AddFaultCode(wErrorCode);
        return wResult;

    }

    @Override
    public ServiceResult<List<EXCStatRate>> EXC_GetDeviceRateList(BMSEmployee wLoginUser, int wUnusualType,
                                                                  int wDeviceID, int wStationID, int wStatType,
                                                                  Calendar wStartDate, Calendar wEndDate) {
        ServiceResult<List<EXCStatRate>> wResult = new ServiceResult<>();
        OutResult<Integer> wErrorCode = new OutResult<>(0);
        wResult.Result = EXCUnusualTaskDAO.getInstance().EXC_GetDeviceRateList(wLoginUser, wUnusualType, wDeviceID,
                wStationID, wStatType, wStartDate, wEndDate, wErrorCode);
        wResult.AddFaultCode(wErrorCode);
        return wResult;

    }

    @Override
    public ServiceResult<List<EXCStatRate>> EXC_GetTypeRateList(BMSEmployee wLoginUser, int wUnusualType,
                                                                int wDeviceID, int wStationID,
                                                                Calendar wStartDate, Calendar wEndDate) {
        ServiceResult<List<EXCStatRate>> wResult = new ServiceResult<>();
        OutResult<Integer> wErrorCode = new OutResult<>(0);
        wResult.Result = EXCUnusualTaskDAO.getInstance().EXC_GetTypeRateList(wLoginUser, wUnusualType, wDeviceID,
                wStationID, wStartDate, wEndDate, wErrorCode);
        wResult.AddFaultCode(wErrorCode);
        return wResult;

    }

    @Override
    public ServiceResult<List<EXCStatRate>> EXC_GetStationRateList(BMSEmployee wLoginUser, int wUnusualType,
                                                                   int wDeviceID, int wStationID,
                                                                   Calendar wStartDate, Calendar wEndDate) {
        ServiceResult<List<EXCStatRate>> wResult = new ServiceResult<>();
        OutResult<Integer> wErrorCode = new OutResult<>(0);
        wResult.Result = EXCUnusualTaskDAO.getInstance().EXC_GetStationRateList(wLoginUser, wUnusualType, wDeviceID,
                wStationID, wStartDate, wEndDate, wErrorCode);
        wResult.AddFaultCode(wErrorCode);
        return wResult;

    }

    @Override
    public ServiceResult<List<EXCStatRate>> EXC_GetDeviceRateList(BMSEmployee wLoginUser, int wUnusualType,
                                                                  int wDeviceID, int wStationID,
                                                                  Calendar wStartDate, Calendar wEndDate) {
        ServiceResult<List<EXCStatRate>> wResult = new ServiceResult<>();
        OutResult<Integer> wErrorCode = new OutResult<>(0);
        wResult.Result = EXCUnusualTaskDAO.getInstance().EXC_GetDeviceRateList(wLoginUser, wUnusualType, wDeviceID,
                wStationID, wStartDate, wEndDate, wErrorCode);
        wResult.AddFaultCode(wErrorCode);
        return wResult;

    }

    @Override
    public ServiceResult<Integer> EXC_AutoSendReportExc(BMSEmployee wLoginUser, int wResponsorID, int wStationID,
                                                        String wRemark) {
        ServiceResult<Integer> wResult = new ServiceResult<>(0);
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            //②启动流程
            EXCUnusualTask wTask = null;
            ServiceResult<EXCUnusualTask> excUnusualTaskServiceResult =
                    EXCServiceImpl.getInstance().BPM_QueryDefaultTask(wLoginUser, -1, 2001);
            if (excUnusualTaskServiceResult.Result == null || excUnusualTaskServiceResult.Result.ID <= 0) {
                ServiceResult<EXCUnusualTask> excUnusualTaskServiceResult1 =
                        EXCServiceImpl.getInstance().BPM_CreateTask(wLoginUser, BPMEventModule.Exception_HANDLE);
                wTask = excUnusualTaskServiceResult1.Result;
            } else {
                wTask = excUnusualTaskServiceResult.Result;
            }
            if (wTask == null || wTask.ID <= 0) {
                wResult.FaultCode += "BPM_CreateTask error!";
                return wResult;
            }

            if (wTask.FlowID <= 0) {
                wTask.FlowID = BPMServiceImpl.getInstance().BPM_CreateProcess(wLoginUser,
                        BPMEventModule.Exception_HANDLE, wTask.getID(), wTask).Info(Integer.class);
            }
            if (wTask.FlowID <= 0) {
                wResult.FaultCode += "创建流程失败！";
                return wResult;
            }
            ServiceResult<EXCUnusualTask> excUnusualTaskServiceResult1 =
                    EXCServiceImpl.getInstance().BPM_SubmitTask(wLoginUser, wTask);
            if (excUnusualTaskServiceResult1.ErrorCode != 0) {
                wResult.FaultCode += excUnusualTaskServiceResult1.getFaultCode();
                return wResult;
            }

            List<BPMActivitiTask> wBPMActivitiTaskList =
                    BPMServiceImpl.getInstance().BPM_GetTaskListByInstance(wLoginUser,
                                    wTask.FlowID)
                            .List(BPMActivitiTask.class);
            if (wBPMActivitiTaskList == null || wBPMActivitiTaskList.size() <= 0) {
                wResult.FaultCode += "BPM_GetTaskListByInstance error!";
                return wResult;
            }
            //①数据准备
            Map<String, Object> wData = EXC_GetCompleteData(wLoginUser, wTask, wResponsorID, wStationID, wRemark,
                    wErrorCode);
            if (wData.size() <= 0) {
                wResult.FaultCode += "获取任务数据失败！";
                return wResult;
            }
            //③完成任务
            String wMsg = EXC_CompleteTask(wLoginUser, wBPMActivitiTaskList.get(0).ID, wTask, wData);
            if (StringUtils.isNotEmpty(wMsg)) {
                wResult.FaultCode += wMsg;
                return wResult;
            }

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error(e.toString());
        }
        return wResult;
    }

    /**
     * 获取提交数据
     */
    private Map<String, Object> EXC_GetCompleteData(BMSEmployee wLoginUser, EXCUnusualTask wTask,
                                                    int wResponsorID, int wStationID, String wRemark,
                                                    OutResult<Integer> wErrorCode) {
        Map<String, Object> wResult = new HashMap<>();
        try {
            Map<String, Object> wParams = new HashMap<String, Object>();
            wParams.put("ID", wStationID);
            FMCStation fmcStation = mFMCStationService.SelectPO(wLoginUser, wParams,
                    wErrorCode);
            if (fmcStation == null || fmcStation.ID <= 0) {
                return wResult;
            }

            wTask.StationID = fmcStation.ID;
            wTask.StationCode = fmcStation.Code;
            wTask.StationName = fmcStation.Name;
            String wStationID_txt_ = StringUtils.Format("{0}【{1}】", fmcStation.Name, fmcStation.Code);

            if (fmcStation.DeviceID != null && fmcStation.DeviceID.size() > 0) {
                wTask.DeviceID = fmcStation.DeviceID.get(0);
                wTask.DeviceName = fmcStation.DeviceName.split(",")[0];
                wTask.DeviceCode = fmcStation.DeviceCode.split(",")[0];
            }

            //获取系统配置
            String sys_report_exc_code = BFCSystemConfigDAO.getInstance().BFC_GetValueByName(wLoginUser, -1,
                    "Sys_Report_Exc_Code", wErrorCode);
            if (StringUtils.isEmpty(sys_report_exc_code)) {
                return wResult;
            }

            //根据异常知识库编码查询知识库
            wParams.clear();
            wParams.put("CodeEQ", sys_report_exc_code);
            DMSFaultBase dmsFaultBase = mDMSFaultBaseService.SelectPO(wLoginUser, wParams,
                    wErrorCode);
            if (dmsFaultBase == null || dmsFaultBase.ID <= 0) {
                return wResult;
            }

            //判断是否已发起此报工异常，若存在，则返回
            wParams.clear();
            wParams.put("ExcRemark", wRemark);
            wParams.put("FaultBaseID", dmsFaultBase.ID);
            List<EXCUnusualTask> excUnusualTasks = mEXCUnusualTaskService.SelectPOList(wLoginUser, wParams,
                    Pagination.getNewMaxSize(),
                    wErrorCode);
            if (excUnusualTasks.size() > 0) {
                return wResult;
            }

            wTask.FaultBaseID = dmsFaultBase.ID;
            String wFaultBaseID_txt_ = StringUtils.Format("{0}【{1}】", dmsFaultBase.Code, dmsFaultBase.Description);

            wParams.clear();
            wParams.put("ID", wResponsorID);
            BMSEmployee bmsEmployee = mBMSEmployeeService.SelectPO(wLoginUser, wParams,
                    wErrorCode);
            if (bmsEmployee == null || bmsEmployee.ID <= 0) {
                return wResult;
            }

            wTask.HandleID = wResponsorID;
            wTask.HandleName = bmsEmployee.Name;
            wTask.ExcRemark = wRemark;
            wTask.UnusualRemark = wRemark;

            wTask.UnusualType = 5;
            wTask.UnusualTypeText = "其他异常";

            wTask.Status = 2;

            wResult.put("Active", wTask.Active);
            wResult.put("AssetInfoID", wTask.AssetInfoID);
            wResult.put("Code", wTask.Code);
            wResult.put("CreateTime", wTask.CreateTime);
            wResult.put("CreatorID", wTask.CreatorID);
            wResult.put("CreatorName", wTask.CreatorName);
            wResult.put("Description", wTask.Description);
            wResult.put("DeviceCode", wTask.DeviceCode);
            wResult.put("DeviceID", wTask.DeviceID);//设备ID
            wResult.put("DeviceID_txt_", wTask.DeviceName);
            wResult.put("DeviceName", wTask.DeviceName);
            wResult.put("DeviceTypeID", wTask.DeviceTypeID);
            wResult.put("EditTime", wTask.EditTime);
            wResult.put("EditorID", wTask.EditorID);
            wResult.put("EditorName", wTask.EditorName);
            wResult.put("ExcFileUrl", wTask.ExcFileUrl);
            wResult.put("ExcFileUrl_txt_", "");
            wResult.put("ExcRemark", wTask.ExcRemark);
            wResult.put("ExcRemark_txt_", wTask.ExcRemark);
            wResult.put("FaultBaseID", wTask.FaultBaseID);//异常知识库
            wResult.put("FaultBaseID_txt_", wFaultBaseID_txt_);
            wResult.put("FlowID", wTask.FlowID);
            wResult.put("FlowType", wTask.FlowType);
            wResult.put("FollowerID", wTask.FollowerID);
            wResult.put("FollowerName", wTask.FollowerName);
            wResult.put("HandleID", wTask.HandleID);//处理人
            wResult.put("HandleID_txt_", wTask.HandleName);
            wResult.put("HandleName", wTask.HandleName);
            wResult.put("HandleTime", wTask.HandleTime);
            wResult.put("ID", wTask.ID);
            wResult.put("ImageList", "");//图片
            wResult.put("ImageList_txt_", "");
            wResult.put("ModelID", wTask.ModelID);
            wResult.put("Name", wTask.Name);
            wResult.put("NewExcCode", wTask.NewExcCode);
            wResult.put("NewExcCode_txt_", "");
            wResult.put("NewExcDescription", wTask.NewExcDescription);
            wResult.put("NewExcDescription_txt_", "");
            wResult.put("NewExcMethods", wTask.NewExcMethods);
            wResult.put("NewExcMethods_txt_", "");
            wResult.put("NewExcUrls", wTask.NewExcUrls);
            wResult.put("NewExcUrls_txt_", "");
            wResult.put("PositionText", wTask.PositionText);
            wResult.put("Remark", wRemark);//备注
            wResult.put("Remark_txt_", wRemark);
            wResult.put("StationCode", wTask.StationCode);//工位
            wResult.put("StationID", wTask.StationID);
            wResult.put("StationID_txt_", wStationID_txt_);
            wResult.put("StationName", wTask.StationName);
            wResult.put("Status", "2");//状态
            wResult.put("StatusText", wTask.StatusText);
            wResult.put("StepID", wTask.StepID);
            wResult.put("TagTypes", wTask.TagTypes);
            wResult.put("UnusualRemark", wTask.UnusualRemark);
            wResult.put("UnusualRemark_txt_", wTask.UnusualRemark);
            wResult.put("UnusualType", wTask.UnusualType);//异常类型
            wResult.put("UnusualTypeText", wTask.UnusualTypeText);
            wResult.put("UnusualType_txt_", wTask.UnusualTypeText);
            wResult.put("UpFlowID", wTask.UpFlowID);
            wResult.put("UpFlowName", wTask.UpFlowName);
        } catch (Exception ex) {
            log.error("EXC_GetCompleteData", ex);
        }
        return wResult;
    }

    /**
     * 完成异常任务
     */
    private String EXC_CompleteTask(BMSEmployee wLoginUser, String wTaskID, EXCUnusualTask wTask,
                                    Map<String, Object> wData) {
        String wResult = "";
        try {
            // ①判断任务是否已完成(防止任务重复提交)
            BPMActivitiHisTask wHisTask =
                    BPMServiceImpl.getInstance().BPM_GetTask(wLoginUser, StringUtils.parseInt(wTaskID)).Info(BPMActivitiHisTask.class);
            if (wHisTask == null || StringUtils.isEmpty(wHisTask.ID)) {
                wResult = "提示：该任务不存在!";
                return wResult;
            } else if (wHisTask.Status == BPMHistoryTaskStatus.NomalFinished.getValue()
                    || wHisTask.Status == BPMHistoryTaskStatus.Canceled.getValue()) {
                wResult = "提示：该任务已完成或已取消!";
                return wResult;
            }

            int wModuleID = wTask.getFlowType();
            BPMEventModule wEventID = BPMEventModule.getEnumType(wModuleID);

            ServiceResult wServiceResult = null;
            BPMActivitiProcessInstance wBPMActivitiProcessInstance = null;

            ServiceResult<Boolean> wServiceResultBool = new ServiceResult<>(false);

            // ①提交任务单
            wServiceResultBool = BPMServiceImpl.getInstance().BPM_MsgUpdate(wLoginUser, StringUtils.parseInt(wTaskID)
                    , 0, wTask,
                    wData);
            if (wServiceResultBool.getResult() || !StringUtils.isEmpty(wServiceResultBool.getFaultCode())) {
                wResult = "提交失败:" + wServiceResultBool.getFaultCode();
                return wResult;
            }
            wServiceResult = EXCServiceImpl.getInstance().BPM_SubmitTask(wLoginUser, wTask);

            wBPMActivitiProcessInstance = BPMServiceImpl.getInstance().BPM_GetInstanceByID(wLoginUser, wTask.FlowID)
                    .Info(BPMActivitiProcessInstance.class);

            /*
             * 判断流程关闭
             */
            if (wBPMActivitiProcessInstance.DurationInMillis != null
                    && wBPMActivitiProcessInstance.DurationInMillis > 0
                    && StringUtils.isEmpty(wBPMActivitiProcessInstance.DeleteReason)
                    && (wTask.Status != BPMTaskStatus.Confirm.getValue() && wTask.Status != BPMTaskStatus.Rejected.getValue())) {
                // ①若流程关闭且状态非正常关闭与异常关闭则改为正常关闭
                wTask.Status = BPMTaskStatus.Confirm.getValue();
                wServiceResult = EXCServiceImpl.getInstance().BPM_SubmitTask(wLoginUser, wTask);
            }
        } catch (Exception ex) {
            log.error("EXC_CompleteTask", ex);
        }
        return wResult;
    }

    //endregion

    //region 停线停序

    @Override
    public ServiceResult<Integer> EXC_SubmitLineStop(BMSEmployee wLoginUser, EXCLineStop wEXCLineStop, int wStatus) {
        ServiceResult<Integer> wResult = new ServiceResult<>(0);
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            if (wEXCLineStop.PartPointList == null || wEXCLineStop.PartPointList.size() <= 0 || wEXCLineStop.OrderID <= 0) {
                wResult.FaultCode += ExceptionTypes.Parameter.getLabel();
                return wResult;
            }

            List<Integer> wRoutePartPointIDList =
                    wEXCLineStop.PartPointList.stream().map(p -> p.RoutePartPointID).distinct().collect(Collectors.toList());

            Map<String, Object> wParams = new HashMap<String, Object>();
            List<APSTaskPartPoint> wAPSTaskPartPointList;
            switch (EXCLineStopStatus.getEnumType(wStatus)) {
                case Stoping: {
                    wEXCLineStop.ConfirmedID = wLoginUser.ID;
                    //开工工序任务暂停
                    wParams.put("OrderID", wEXCLineStop.OrderID);
                    wParams.put("RoutePartPointID", StringUtils.Join(",", wRoutePartPointIDList));
                    wParams.put("Active", 1);
                    wParams.put("Status", APSTaskStatus.Started.getValue());
                    wParams.put("IsCurrent", 1);
                    wAPSTaskPartPointList = mAPSTaskPartPointService.SelectPOList(wLoginUser,
                            wParams, Pagination.getNewMaxSize(),
                            wErrorCode);
                    if (wAPSTaskPartPointList == null || wAPSTaskPartPointList.size() <= 0) {
                        return wResult;
                    }
                    for (APSTaskPartPoint wAPSTaskPartPoint : wAPSTaskPartPointList) {
                        wAPSTaskPartPoint.Description = "系统停序";
                        wAPSTaskPartPoint.Status = APSTaskStatus.Suspend.getValue();
                        wAPSTaskPartPoint.setUserInfo(wLoginUser);
                    }
                    mAPSTaskPartPointService.UpdatePoList(wLoginUser, wAPSTaskPartPointList, wErrorCode);
                    //已开工的日计划暂停
                    wParams.clear();
                    wParams.put("TaskPartPointID", StringUtils.Join(",",
                            wAPSTaskPartPointList.stream().map(p -> p.ID).collect(Collectors.toList())));
                    wParams.put("Status", APSTaskStatus.Started.getValue());
                    wParams.put("Active", 1);
                    List<APSTaskPartPointDay> apsTaskPartPointDays =
                            mAPSTaskPartPointDayService.SelectPOList(wLoginUser, wParams, Pagination.getNewMaxSize(),
                                    wErrorCode);
                    if (apsTaskPartPointDays.size() > 0) {
                        apsTaskPartPointDays.forEach(p -> {
                            p.Status = APSTaskStatus.Suspend.getValue();
                            p.setUserInfo(wLoginUser);
                        });
                        mAPSTaskPartPointDayService.UpdatePoList(wLoginUser, apsTaskPartPointDays, wErrorCode);
                    }
                    //已开工的派工单暂停
                    wParams.clear();
                    wParams.put("TaskPartPointID", StringUtils.Join(",",
                            wAPSTaskPartPointList.stream().map(p -> p.ID).collect(Collectors.toList())));
                    wParams.put("Active", 1);
                    wParams.put("Status", SFCTaskStatus.Doing.getValue());
                    List<SFCTaskSelf> sfcTaskSelves = mSFCTaskSelfService.SelectPOList(wLoginUser, wParams,
                            Pagination.getNewMaxSize(),
                            wErrorCode);
                    if (sfcTaskSelves.size() > 0) {
                        sfcTaskSelves.forEach(p -> {
                            p.Status = SFCTaskStatus.Suspend.getValue();
                            p.setUserInfo(wLoginUser);
                        });
                        mSFCTaskSelfService.UpdatePoList(wLoginUser, sfcTaskSelves, wErrorCode);
                    }
                }
                break;
                case Finished: {
                    wEXCLineStop.CancelPersonID = wLoginUser.ID;
                    //工序任务取消暂停
                    wParams.put("OrderID", wEXCLineStop.OrderID);
                    wParams.put("RoutePartPointID", StringUtils.Join(",", wRoutePartPointIDList));
                    wParams.put("Active", 1);
                    wParams.put("Status", APSTaskStatus.Suspend.getValue());
                    wParams.put("IsCurrent", 1);
                    wAPSTaskPartPointList = mAPSTaskPartPointService.SelectPOList(wLoginUser,
                            wParams, Pagination.getNewMaxSize(),
                            wErrorCode);
                    if (wAPSTaskPartPointList == null || wAPSTaskPartPointList.size() <= 0) {
                        return wResult;
                    }
                    for (APSTaskPartPoint wAPSTaskPartPoint : wAPSTaskPartPointList) {
                        wAPSTaskPartPoint.Description = StringUtils.Format("系统停序恢复");
                        wAPSTaskPartPoint.Status = APSTaskStatus.Started.getValue();
                        wAPSTaskPartPoint.setUserInfo(wLoginUser);
                    }
                    mAPSTaskPartPointService.UpdatePoList(wLoginUser, wAPSTaskPartPointList, wErrorCode);
                    //已开工的日计划取消暂停
                    wParams.clear();
                    wParams.put("TaskPartPointID", StringUtils.Join(",",
                            wAPSTaskPartPointList.stream().map(p -> p.ID).collect(Collectors.toList())));
                    wParams.put("Status", APSTaskStatus.Suspend.getValue());
                    wParams.put("Active", 1);
                    List<APSTaskPartPointDay> apsTaskPartPointDays =
                            mAPSTaskPartPointDayService.SelectPOList(wLoginUser, wParams, Pagination.getNewMaxSize(),
                                    wErrorCode);
                    if (apsTaskPartPointDays.size() > 0) {
                        apsTaskPartPointDays.forEach(p -> {
                            p.Status = APSTaskStatus.Started.getValue();
                            p.setUserInfo(wLoginUser);
                        });
                        mAPSTaskPartPointDayService.UpdatePoList(wLoginUser, apsTaskPartPointDays, wErrorCode);
                    }
                    //已开工的派工单取消暂停
                    wParams.clear();
                    wParams.put("TaskPartPointID", StringUtils.Join(",",
                            wAPSTaskPartPointList.stream().map(p -> p.ID).collect(Collectors.toList())));
                    wParams.put("Active", 1);
                    wParams.put("Status", SFCTaskStatus.Suspend.getValue());
                    List<SFCTaskSelf> sfcTaskSelves = mSFCTaskSelfService.SelectPOList(wLoginUser, wParams,
                            Pagination.getNewMaxSize(),
                            wErrorCode);
                    if (sfcTaskSelves.size() > 0) {
                        sfcTaskSelves.forEach(p -> {
                            p.Status = SFCTaskStatus.Doing.getValue();
                            p.setUserInfo(wLoginUser);
                        });
                        mSFCTaskSelfService.UpdatePoList(wLoginUser, sfcTaskSelves, wErrorCode);
                    }
                }
                break;
                case Canceled:
                    wEXCLineStop.CancelPersonID = wLoginUser.ID;
                    break;
                default:
                    break;
            }

            wEXCLineStop.setUserInfo(wLoginUser);
            wEXCLineStop.Status = wStatus;
            if (wEXCLineStop.Status == EXCLineStopStatus.Finished.getValue()) {
                wEXCLineStop.StopEndDate = Calendar.getInstance();
            }
            wResult.Result = mEXCLineStopService.UpdatePo(wLoginUser, wEXCLineStop, wErrorCode);

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error("EXC_SubmitLineStop", e);
        }
        return wResult;
    }

    @Override
    public ServiceResult<Boolean> EXC_IsRoutePartPointStop(BMSEmployee wLoginUser, int wOrderID,
                                                           int wRoutePartPointID) {
        ServiceResult<Boolean> wResult = new ServiceResult<>();
        wResult.Result = false;
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            Map<String, Object> wParams = new HashMap<String, Object>();
            wParams.put("OrderID", wOrderID);
            wParams.put("Status", EXCLineStopStatus.Stoping.getValue());
            List<EXCLineStop> wEXCLineStopList = mEXCLineStopService.SelectPOList(wLoginUser, wParams,
                    Pagination.getNewMaxSize(),
                    wErrorCode);
            if (wEXCLineStopList == null || wEXCLineStopList.size() <= 0) {
                wResult.Result = false;
                return wResult;
            }

            if (wEXCLineStopList.stream().anyMatch(p -> p.PartPointList.stream().anyMatch(q -> q.RoutePartPointID == wRoutePartPointID))) {
                wResult.Result = true;
                return wResult;
            }

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error("EXC_IsRoutePartPointStop", e);
        }
        return wResult;
    }

    //endregion

    //region 返工返修

    @Override
    public ServiceResult<Integer> EXC_SubmitProductRepair(BMSEmployee wLoginUser, EXCProductRepair wEXCProductRepair,
                                                          int wStatus) {
        ServiceResult<Integer> wResult = new ServiceResult<>(0);
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            wEXCProductRepair.setUserInfo(wLoginUser);
            int wAffectRows;

            switch (EXCProductRepairStatus.getEnumType(wStatus)) {
                case Default://保存
                case Revoke://撤销
                    wEXCProductRepair.RepairID = wLoginUser.ID;
                    wEXCProductRepair.Status = wStatus;
                    wAffectRows = mEXCProductRepairService.UpdatePo(wLoginUser, wEXCProductRepair, wErrorCode);
                    if (wAffectRows <= 0) {
                        wResult.FaultCode += ExceptionTypes.DBSQL.getValue();
                        return wResult;
                    }
                    break;
                case InProgress://提交
                    wEXCProductRepair.Status = wStatus;
                    wAffectRows = mEXCProductRepairService.UpdatePo(wLoginUser, wEXCProductRepair, wErrorCode);
                    if (wAffectRows <= 0) {
                        wResult.FaultCode += ExceptionTypes.DBSQL.getValue();
                        return wResult;
                    }

                    //触发返修日计划的生成逻辑
                    TriggerRepairDayPlan(wLoginUser, wEXCProductRepair, wErrorCode);

                    //成品返工需要将成品元件记录增加返工标记
                    TaskTimerUtils.AddTask("AddReworkFlag",
                            () -> AddReworkFlag(wLoginUser, wEXCProductRepair, wErrorCode)
                    );
                    break;
                case ConfirmClose://确认关闭
                    wEXCProductRepair.Status = wStatus;
                    wEXCProductRepair.ConfirmedID = wLoginUser.ID;
                    wAffectRows = mEXCProductRepairService.UpdatePo(wLoginUser, wEXCProductRepair, wErrorCode);
                    if (wAffectRows <= 0) {
                        wResult.FaultCode += ExceptionTypes.DBSQL.getValue();
                        return wResult;
                    }
                    break;
                default:
                    wResult.FaultCode += ExceptionTypes.Parameter.getLabel();
                    return wResult;
            }

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error("EXC_SubmitProductRepair", e);
        }
        return wResult;
    }

    /**
     * 返工优化：成品返工需要将成品元件记录增加返工标记
     */
    private void AddReworkFlag(BMSEmployee wLoginUser, EXCProductRepair wEXCProductRepair,
                               OutResult<Integer> wErrorCode) {
        try {
            Map<String, Object> wParams = new HashMap<String, Object>();
            for (String wWorkpieceNo : wEXCProductRepair.WorkpieceNoList) {
                wParams.clear();
                wParams.put("Code", wWorkpieceNo);
                SFCWorkpieceRecord wSFCWorkpieceRecord = mSFCWorkpieceRecordService.SelectPO(wLoginUser, wParams,
                        wErrorCode);
                if (wSFCWorkpieceRecord == null || wSFCWorkpieceRecord.ID <= 0) {
                    continue;
                }
                //箱体返工，成品、芯子以及元件增加返工标记
                if (wSFCWorkpieceRecord.ComponentType == PDMComponentTypes.Box.getValue()) {
                    //更新成品
                    wParams.clear();
                    wParams.put("BoxNo", wSFCWorkpieceRecord.Code);
                    wParams.put("ComponentType", PDMComponentTypes.Product.getValue());
                    List<SFCWorkpieceRecord> sfcWorkpieceRecords = mSFCWorkpieceRecordService.SelectPOList(wLoginUser
                            , wParams, Pagination.getNewMaxSize(),
                            wErrorCode);
                    for (SFCWorkpieceRecord sfcWorkpieceRecord : sfcWorkpieceRecords) {
                        sfcWorkpieceRecord.ReworkFlag = 1;
                        mSFCWorkpieceRecordService.UpdatePo(wLoginUser, sfcWorkpieceRecord, wErrorCode);
                        //更新芯子
                        wParams.clear();
                        wParams.put("PackageNo", sfcWorkpieceRecord.Code);
                        wParams.put("ComponentType", PDMComponentTypes.Core.getValue());
                        List<SFCWorkpieceRecord> sfcWorkpieceRecords1 =
                                mSFCWorkpieceRecordService.SelectPOList(wLoginUser
                                        , wParams, Pagination.getNewMaxSize(),
                                        wErrorCode);
                        for (SFCWorkpieceRecord workpieceRecord : sfcWorkpieceRecords1) {
                            workpieceRecord.ReworkFlag = 1;
                            mSFCWorkpieceRecordService.UpdatePo(wLoginUser, workpieceRecord, wErrorCode);
                            //更新元件
                            wParams.clear();
                            wParams.put("CaseNo", workpieceRecord.Code);
                            wParams.put("ComponentType", PDMComponentTypes.Component.getValue());
                            List<SFCWorkpieceRecord> sfcWorkpieceRecords2 =
                                    mSFCWorkpieceRecordService.SelectPOList(wLoginUser
                                            , wParams, Pagination.getNewMaxSize(),
                                            wErrorCode);
                            for (SFCWorkpieceRecord record : sfcWorkpieceRecords2) {
                                record.ReworkFlag = 1;
                                mSFCWorkpieceRecordService.UpdatePo(wLoginUser, record, wErrorCode);
                            }
                        }
                    }
                }
                //成品返工，芯子以及元件增加返工标记
                else if (wSFCWorkpieceRecord.ComponentType == PDMComponentTypes.Product.getValue()) {
                    //更新芯子
                    wParams.clear();
                    wParams.put("PackageNo", wSFCWorkpieceRecord.Code);
                    wParams.put("ComponentType", PDMComponentTypes.Core.getValue());
                    List<SFCWorkpieceRecord> sfcWorkpieceRecords = mSFCWorkpieceRecordService.SelectPOList(wLoginUser
                            , wParams, Pagination.getNewMaxSize(),
                            wErrorCode);
                    for (SFCWorkpieceRecord sfcWorkpieceRecord : sfcWorkpieceRecords) {
                        sfcWorkpieceRecord.ReworkFlag = 1;
                        mSFCWorkpieceRecordService.UpdatePo(wLoginUser, sfcWorkpieceRecord, wErrorCode);
                        //更新元件
                        wParams.clear();
                        wParams.put("CaseNo", sfcWorkpieceRecord.Code);
                        wParams.put("ComponentType", PDMComponentTypes.Component.getValue());
                        List<SFCWorkpieceRecord> sfcWorkpieceRecords1 =
                                mSFCWorkpieceRecordService.SelectPOList(wLoginUser, wParams, Pagination.getNewMaxSize(),
                                        wErrorCode);
                        for (SFCWorkpieceRecord workpieceRecord : sfcWorkpieceRecords1) {
                            workpieceRecord.ReworkFlag = 1;
                            mSFCWorkpieceRecordService.UpdatePo(wLoginUser, workpieceRecord, wErrorCode);
                        }
                    }
                }
                //芯子返工，元件增加返工标记
                else if (wSFCWorkpieceRecord.ComponentType == PDMComponentTypes.Core.getValue()) {
                    wParams.clear();
                    wParams.put("CaseNo", wSFCWorkpieceRecord.Code);
                    wParams.put("ComponentType", PDMComponentTypes.Component.getValue());
                    List<SFCWorkpieceRecord> sfcWorkpieceRecords = mSFCWorkpieceRecordService.SelectPOList(wLoginUser
                            , wParams, Pagination.getNewMaxSize(),
                            wErrorCode);
                    for (SFCWorkpieceRecord sfcWorkpieceRecord : sfcWorkpieceRecords) {
                        sfcWorkpieceRecord.ReworkFlag = 1;
                        mSFCWorkpieceRecordService.UpdatePo(wLoginUser, sfcWorkpieceRecord, wErrorCode);
                    }
                }
            }
        } catch (Exception ex) {
            log.error("AddReworkFlag", ex);
        }
    }

    /**
     * 生成返修日计划
     */
    private void TriggerRepairDayPlan(BMSEmployee wLoginUser, EXCProductRepair wEXCProductRepair,
                                      OutResult<Integer> wErrorCode) {
        try {
            List<Integer> wRoutePartPointIDList =
                    wEXCProductRepair.PartPointList.stream().map(p -> p.RoutePartPointID).distinct().collect(Collectors.toList());

            Map<String, Object> wParams = new HashMap<String, Object>();
            wParams.put("OrderID", wEXCProductRepair.OrderID);
            wParams.put("RoutePartPointID", StringUtils.Join(",", wRoutePartPointIDList));
            List<APSTaskPartPointDay> wAPSTaskPartPointDayList = mAPSTaskPartPointDayService.SelectPOList(wLoginUser,
                    wParams, Pagination.getNewMaxSize(),
                    wErrorCode);

            //计算当前班次
            List<FMCShift> wFMCShiftList =
                    FMCServiceImpl.getInstance().FMC_QueryShiftList(wLoginUser, 9, 0, 0, 0,
                            Pagination.getNewMaxSize()).Result;
            if (wFMCShiftList == null || wFMCShiftList.size() <= 0) {
                log.info("TriggerRepairDayPlan:未查询到工厂班次设置，请联系系统管理员!");
                return;
            }

            int wYear = Calendar.getInstance().get(Calendar.YEAR);
            int wMonth = Calendar.getInstance().get(Calendar.MONTH);
            int wDate = Calendar.getInstance().get(Calendar.DATE);

            FMCShift wCurrentShift = new FMCShift();
            for (FMCShift wFMCShift : wFMCShiftList) {
                wFMCShift.StartTime.set(wYear, wMonth, wDate);
                wFMCShift.EndTime.set(wYear, wMonth, wDate);
                if (Calendar.getInstance().compareTo(wFMCShift.StartTime) >= 0 && Calendar.getInstance().compareTo(wFMCShift.EndTime) <= 0) {
                    wCurrentShift = wFMCShift;
                }
            }
            if (wCurrentShift.ID <= 0) {
                log.info("TriggerRepairDayPlan:未查询到当前班次信息，请检查班次设置!");
                return;
            }

            Calendar wStationDate = Calendar.getInstance();
            wStationDate.set(Calendar.HOUR_OF_DAY, 0);
            wStationDate.set(Calendar.MINUTE, 0);
            wStationDate.set(Calendar.SECOND, 0);

            for (int wRoutePartPointID : wRoutePartPointIDList) {
                if (wAPSTaskPartPointDayList.stream().noneMatch(p -> p.RoutePartPointID == wRoutePartPointID)) {
                    continue;
                }
                List<APSTaskPartPointDay> wDayPlanList =
                        wAPSTaskPartPointDayList.stream().filter(p -> p.RoutePartPointID == wRoutePartPointID).collect(Collectors.toList());

                APSTaskPartPointDay wAPSTaskPartPointDay =
                        wDayPlanList.stream().max(Comparator.comparing(APSTaskPartPointDay::getCreateTime)).get();
                wAPSTaskPartPointDay.IsRepairPlan = 1;
                wAPSTaskPartPointDay.ID = 0;
                wAPSTaskPartPointDay.Code = "";
                wAPSTaskPartPointDay.ShiftType = wCurrentShift.ShiftType;
                wAPSTaskPartPointDay.StationDate = wStationDate;
                wAPSTaskPartPointDay.ActNum = 0;
                wAPSTaskPartPointDay.Status = APSTaskStatus.Issued.getValue();
                wAPSTaskPartPointDay.ProductRepairID = wEXCProductRepair.ID;
                wAPSTaskPartPointDay.PlantNum = wEXCProductRepair.WorkpieceNoList.size();
                mAPSTaskPartPointDayService.UpdatePo(wLoginUser, wAPSTaskPartPointDay, wErrorCode);
            }
        } catch (Exception ex) {
            log.error("TriggerRepairDayPlan", ex);
        }
    }

    @Override
    public ServiceResult<List<FPCRoutePartPoint>> EXC_QueryRepairPartPointList(BMSEmployee wLoginUser,
                                                                               String wWorkpieceNos) {
        ServiceResult<List<FPCRoutePartPoint>> wResult = new ServiceResult<>();
        wResult.Result = new ArrayList<>();
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            Map<String, Object> wParams = new HashMap<String, Object>();
            wParams.put("WorkpieceCode", wWorkpieceNos);
            List<SFCWorkpieceResume> wSFCWorkpieceResumeList = mSFCWorkpieceResumeService.SelectPOList(wLoginUser,
                    wParams, Pagination.getNewMaxSize(),
                    wErrorCode);
            if (wSFCWorkpieceResumeList == null || wSFCWorkpieceResumeList.size() <= 0) {
                return wResult;
            }

            List<Integer> wRoutePartPointIDList =
                    wSFCWorkpieceResumeList.stream().map(p -> p.RoutePartPointID).distinct().collect(Collectors.toList());
            wParams.clear();
            wResult.Result = mFPCRoutePartPointService.SelectPOList(wLoginUser, wRoutePartPointIDList, wParams,
                    Pagination.getNewMaxSize(), wErrorCode);

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error("EXC_QueryRepairPartPointList", e);
        }
        return wResult;
    }

    @Override
    public ServiceResult<List<SFCWorkpieceRecord>> EXC_QueryWorkpieceCodeList(BMSEmployee wLoginUser, int wOrderID) {
        ServiceResult<List<SFCWorkpieceRecord>> wResult = new ServiceResult<>();
        wResult.Result = new ArrayList<>();
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            Map<String, Object> wParams = new HashMap<String, Object>();
            wParams.put("OrderID", wOrderID);
            wParams.put("CheckResult", SFCWorkpieceCheckResult.Bad.getValue());
            List<SFCWorkpieceRecord> wSFCWorkpieceRecordList = mSFCWorkpieceRecordService.SelectPOList(wLoginUser,
                    wParams, Pagination.getNewMaxSize(),
                    wErrorCode);
            if (wSFCWorkpieceRecordList == null || wSFCWorkpieceRecordList.size() <= 0) {
                return wResult;
            }

            wParams.clear();
            wParams.put("OrderID", wOrderID);
            wParams.put("Status", "0,1,2,3");
            List<EXCProductRepair> wEXCProductRepairList = mEXCProductRepairService.SelectPOList(wLoginUser, wParams,
                    Pagination.getNewMaxSize(),
                    wErrorCode);
            for (SFCWorkpieceRecord wSFCWorkpieceRecord : wSFCWorkpieceRecordList) {
                if (wEXCProductRepairList.stream().anyMatch(p -> p.WorkpieceNoList.stream().anyMatch(q -> q.equals(wSFCWorkpieceRecord.Code)))) {
                    continue;
                }
                wResult.Result.add(wSFCWorkpieceRecord);
            }

            // 排序
            wResult.Result.sort(Comparator.comparing(SFCWorkpieceRecord::getCode));

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error("EXC_QueryWorkpieceCodeList", e);
        }
        return wResult;
    }

    @Override
    public ServiceResult<Integer> EXC_ProductRepairItemStatusUpdateLogic(BMSEmployee wLoginUser,
                                                                         SFCTaskIPT wSFCTaskIPT, boolean wIsReport) {
        ServiceResult<Integer> wResult = new ServiceResult<>(0);
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            //①查询日计划
            Map<String, Object> wParams = new HashMap<String, Object>();
            wParams.put("ID", wSFCTaskIPT.TaskPartPointDayID);
            APSTaskPartPointDay wAPSTaskPartPointDay = mAPSTaskPartPointDayService.SelectPO(wLoginUser, wParams,
                    wErrorCode);
            if (wAPSTaskPartPointDay == null || wAPSTaskPartPointDay.ID <= 0 || wAPSTaskPartPointDay.IsRepairPlan != 1
                    || wAPSTaskPartPointDay.ProductRepairID <= 0) {
                return wResult;
            }
            //②查询返修记录
            wParams.clear();
            wParams.put("TaskID", wAPSTaskPartPointDay.ProductRepairID);
            List<EXCProductRepairItem> wEXCProductRepairItemList = mEXCProductRepairItemService.SelectPOList(wLoginUser,
                    wParams, Pagination.getNewMaxSize(),
                    wErrorCode);
            if (wEXCProductRepairItemList == null || wEXCProductRepairItemList.size() <= 0) {
                return wResult;
            }
            //③更新返修记录状态
            if (wEXCProductRepairItemList.stream().noneMatch(p -> p.WorkpieceNo.equals(wSFCTaskIPT.ComponentCode)
                    && p.RoutePartPointID == wSFCTaskIPT.RoutePartPointID)) {
                return wResult;
            }
            EXCProductRepairItem wEXCProductRepairItem =
                    wEXCProductRepairItemList.stream().filter(p -> p.WorkpieceNo.equals(wSFCTaskIPT.ComponentCode)
                            && p.RoutePartPointID == wSFCTaskIPT.RoutePartPointID).findFirst().get();
            if (wIsReport) {
                wEXCProductRepairItem.Status = EXCProductRepairItemStatus.Reported.getValue();
                wEXCProductRepairItem.ReportTime = Calendar.getInstance();
            } else {
                wEXCProductRepairItem.CheckTime = Calendar.getInstance();
                if (wSFCTaskIPT.Result == 1) {
                    wEXCProductRepairItem.Status = EXCProductRepairItemStatus.CheckGood.getValue();
                } else if (wSFCTaskIPT.Result == 2) {
                    wEXCProductRepairItem.Status = EXCProductRepairItemStatus.CheckBad.getValue();
                } else {
                    wEXCProductRepairItem.Status = EXCProductRepairItemStatus.InProgress.getValue();
                }
            }

            mEXCProductRepairItemService.UpdatePo(wLoginUser, wEXCProductRepairItem, wErrorCode);
            //④更新返修单的状态
            wParams.clear();
            wParams.put("ID", wAPSTaskPartPointDay.ProductRepairID);
            EXCProductRepair wEXCProductRepair = mEXCProductRepairService.SelectPO(wLoginUser, wParams,
                    wErrorCode);
            if (wEXCProductRepair == null || wEXCProductRepair.ID <= 0) {
                return wResult;
            }

            int wFinishedWorkpiece = 0;
            SFCWorkpieceRecord wSFCWorkpieceRecord;
            for (String wWorkpieceNo : wEXCProductRepair.WorkpieceNoList) {
                wParams.clear();
                wParams.put("Code", wWorkpieceNo);
                wSFCWorkpieceRecord = mSFCWorkpieceRecordService.SelectPO(wLoginUser, wParams,
                        wErrorCode);
                if (wSFCWorkpieceRecord != null && wSFCWorkpieceRecord.ID > 0 && wSFCWorkpieceRecord.Status == SFCTaskStatus.Scarp.getValue()) {
                    wFinishedWorkpiece++;
                    continue;
                }
                int wCount =
                        (int) wEXCProductRepairItemList.stream().filter(p -> p.WorkpieceNo.equals(wWorkpieceNo)
                                && (p.Status == EXCProductRepairItemStatus.CheckBad.getValue() || p.Status == EXCProductRepairItemStatus.Reported.getValue())).count();
                if (wCount == wEXCProductRepair.PartPointList.size()) {
                    wFinishedWorkpiece++;
                }
            }

            //根据返修单查询工序计划
            wParams.clear();
            wParams.put("ProductRepairID", wEXCProductRepair.ID);
            List<APSTaskPartPointDay> wAPSTaskPartPointDayList =
                    mAPSTaskPartPointDayService.SelectPOList(wLoginUser,
                            wParams, Pagination.getNewMaxSize(),
                            wErrorCode);
            //更新进度
            for (APSTaskPartPointDay apsTaskPartPointDay : wAPSTaskPartPointDayList) {
                wParams.clear();
                wParams.put("RoutePartPointID", apsTaskPartPointDay.RoutePartPointID);
                wParams.put("ProductRepairID", wEXCProductRepair.ID);
                wParams.put("Status", SFCTaskStatus.Done.getValue());
                List<SFCTaskIPT> sfcTaskIPTS = mSFCTaskIPTService.SelectPOList(wLoginUser, wParams,
                        Pagination.getNewMaxSize(),
                        wErrorCode);
                apsTaskPartPointDay.ActNum = sfcTaskIPTS.size();
                mAPSTaskPartPointDayService.UpdatePo(wLoginUser, apsTaskPartPointDay, wErrorCode);
            }

            //更新状态
            if (wFinishedWorkpiece == wEXCProductRepair.WorkpieceNoList.size()) {
                wEXCProductRepair.Status = EXCProductRepairStatus.AllCompleted.getValue();
                wEXCProductRepair.setUserInfo(wLoginUser);
                mEXCProductRepairService.UpdatePo(wLoginUser, wEXCProductRepair, wErrorCode);
                for (APSTaskPartPointDay wDayTask : wAPSTaskPartPointDayList) {
                    //工序计划完工
                    wDayTask.setUserInfo(wLoginUser);
                    wDayTask.Status = APSTaskStatus.Done.getValue();
                    mAPSTaskPartPointDayService.UpdatePo(wLoginUser, wDayTask, wErrorCode);
                    //派工计划完工
                    wParams.clear();
                    wParams.put("TaskPartPointDayID", wDayTask.ID);
                    wParams.put("Active", 1);
                    List<SFCTaskSelf> wSFCTaskSelfList = mSFCTaskSelfService.SelectPOList(wLoginUser, wParams,
                            Pagination.getNewMaxSize(),
                            wErrorCode);
                    if (wSFCTaskSelfList != null && wSFCTaskSelfList.size() > 0) {
                        for (SFCTaskSelf wSFCTaskSelf : wSFCTaskSelfList) {
                            wSFCTaskSelf.setUserInfo(wLoginUser);
                            wSFCTaskSelf.Status = SFCTaskStatus.Done.getValue();
                        }
                        mSFCTaskSelfService.UpdatePoList(wLoginUser, wSFCTaskSelfList, wErrorCode);
                    }
                }
            } else if (wFinishedWorkpiece > 0 && wFinishedWorkpiece < wEXCProductRepair.WorkpieceNoList.size()) {
                wEXCProductRepair.Status = EXCProductRepairStatus.PartiallyCompleted.getValue();
                wEXCProductRepair.setUserInfo(wLoginUser);
                mEXCProductRepairService.UpdatePo(wLoginUser, wEXCProductRepair, wErrorCode);
            }

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error("EXC_ProductRepairItemStatusUpdateLogic", e);
        }
        return wResult;
    }

    //endregion
}
